Random musing: TStringList

A while back, Jim McKeeth told me (jokingly, of course) that with a TStringList and a TDataset, you can solve any programming problem.  He also likes to compare TStringList to a Swiss Army Knife, because it can do so many things.  And it sort of made me wonder.  In object-oriented philosophy, a “good” object is supposed to have a single well-defined responsibility.  But I generally see  TStringList being used for three very different things:

  1. As a list of strings, either a simple string list or occasionally as a quick-and-dirty parser by setting the DelimitedText or CommaText properties in order to create a list of strings.
  2. As a string-string key-value pair dictionary, using the .Value property.
  3. As a string-object key-value pair dictionary, using the .Objects property.

You don’t often see the same TStringList use functionality from more than one of the above three modes.  So that makes me wonder, now that we have proper key-value pair dictionaries in the RTL, with better APIs for storing key-value pairs and especially for retrieving the value associated with a certain key than what TStrings provides, what would TStringList be like if Generics.Collections.pas had been available in Delphi 1?

I think there would probably be two predefined classes:

  • TStringList = class(TList<string>);  It would implement CommaText and DelimitedText, and the LoadFromX and SaveToX methods.
  • TStringDictionary = class(TDictionary<string, string>); It would implement LoadFromX and SaveToX,

No predefined string/object dictionary, since they’re easy enough to create yourself and get the right class for the objects.  It seems to me that that would be a more logical design.  But then again, how would that affect the way a bunch of VCL collection controls use custom TStrings descendants as string/object dictionaries?  (TListBox comes to mind.)

It’s an interesting question.  How would having generics available from Delphi 1 have affected the design of TStrings and the VCL in general?  Any thoughts?

P.S. Happy 15th birthday, Delphi!

7 Comments

  1. Jolyon Smith says:

    “How would having generics available from Delphi 1 have affected the design of TStrings and the VCL in general?”

    The short answer: Arguably more “pure” from an OO-theoretician’s p.o.v but a great deal messier and more confusing in practical terms. 🙂

  2. Xepol says:

    “In object-oriented philosophy, a “good” object is supposed to have a single well-defined responsibility.” Theory is great, but it often falls apart even before you hit the implementation stage. If it makes it to the implementation stage untarnished, it will DEFINITELY fall apart then.

    Still, it is nice to have a theoretical meter stick to strive for – even if it is an impossible goal.

    After all, in pure OO, even the strings and numbers are objects. With out that, adding generics at D1, I would have to agree with Jolyon -> A huge, HUGE mess.

    Perhaps the root problem is actually that we are unavoidably mixing OO and non-OO programming concepts together (even if your code was 100% OO, there is still the OS and libraries to deal with! dotNet languages really highlight the disconnect. )

  3. Mason Wheeler says:

    Maybe I should clarify. I don’t like the idea of pure, single-paradigm OO. I think it creates more problems than it solves. I’m just taking about TStringList specifically, which is an object class and part of a (mostly) object-oriented language.

  4. Cameron says:

    TStringList would still be one of the handiest objects even with generics from day one. Generics are great for organizing a more complex group of objects but most of the time when I am dealing with TStringList I am just keeping track of some keys, parsing small CSV/text files or using its Sort/Duplicate functionality. The beauty of TStringList is that it is a simple implementation which means a programmer coming behind me two years from now will be able to easily see what I have done. Generic implementations can often lead to over-engineering and quite frankly if not used responsibly some very annoying bugs. If I wanted to abstract all my types, I would have used Smalltalk back in the day. Often a hard typed class is simply more functional even if it isn’t as flexible.

  5. CR says:

    IMO, it’s probably better that generics weren’t available, or TStrings (and the cleanness of its polymophism) wouldn’t have been invented. As you suggest, the natural approach to TStringList (if it were to have been created in a generics world at all) would have been to derive from TList, not a specialised abstract base class. Polymorphism with the contents of a TListBox, TComboBox, TMemo, etc., wouldn’t then make sense, since it’s the underlying WinAPI control that hold the actual strings, not TListBoxStrings etc.

  6. Fabricio says:

    I agree on Jolyon on this: it would be a mess.
    And add an other responsibility of TStringList: parse simple INI files (those which don’t have sections, just key=value pairs).

  7. Marco van de Voort says:

    I’ve been thinking about this too, and yes, tstringlist implements way, way too much.

    I really would prefer to keep string as native type, and not as object (since if I liked that I wouldn’t be using Delphi in first way). It does have its problem (as in comparison operators can’t be inserted by use of generics)

    TStringlist definitely tries to do too much. Besides the already mentioned stuff (ini file parsing, splitting) etc, I don’t like the way that the internal storage format (one/two arrays) bleed through in the format. The array aspect is what makes inserting into a even a moderately sized ordered array so slow.

    I looked around a bit in the generics units, but they use string nowhere. If people have interesting links I’d be interested.